package com.hmjk.health.background;

import java.util.HashMap;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.format.Time;
import android.util.Log;

import com.hmjk.health.HealthApp;
import com.hmjk.health.background.data.BloodPressureDataUpdated;
import com.hmjk.health.background.data.CareReminderUpdated;
import com.hmjk.health.background.data.DataUpdated;
import com.hmjk.health.background.data.DeviceFaceUpdated;
import com.hmjk.health.background.data.DeviceListUpdated;
import com.hmjk.health.background.data.DeviceLocationQuery;
import com.hmjk.health.background.data.DevicePowerUpdated;
import com.hmjk.health.background.data.DeviceSettingsUpdated;
import com.hmjk.health.background.data.DrugReminderUpdated;
import com.hmjk.health.background.data.DeviceSubInfoUpdate;
import com.hmjk.health.background.data.DeviceSubListUpdate;
import com.hmjk.health.background.data.FamilyListUpdated;
import com.hmjk.health.background.data.FamilyMemberUpdated;
import com.hmjk.health.background.data.GlycoseDataUpdated;
import com.hmjk.health.background.data.GlycoseSetUpdated;
import com.hmjk.health.background.data.MeasureReminderUpdated;
import com.hmjk.health.background.data.MemberFaceUpdated;
import com.hmjk.health.background.data.ToDoUpdated;
import com.hmjk.health.background.data.UserDataUpdated;
import com.hmjk.health.background.data.UserFaceUpdated;
import com.hmjk.health.util.DEV_DATA;

/* 这边处理sqlite数据库的访问，
 * 并且建议个后台的mHandler，UI发起的网络请求先发给这个mHandler，
 * 由mHandler想NetService发起请求，返回的网络数据就会送回mHandler
 * mHandler在后台更新完数据库后，通知UI更新
 * */
public class DataManager {
	private static final String TAG = DataManager.class.getSimpleName();
	private HealthApp mApp = null;
	private HandlerThread mMsgThread = null;
	private DataHandler mHandler = null;
	private boolean firstGrab = false;
	private DatabaseHelper mDBHelper = null;
	
	public static final String DATA_UPDATE_ACTION = "com.hmjk.data.updated";
	public static final String DATA_COMMIT_RESULT = "com.hmjk.data.committed";
	
	/*build user data*/
	public static final String F_USERDATA = "f_userdata"; //1.3.1
	public static final String F_USERFACE = "f_userface"; //1.1.5 & 1.1.6
	public static final String F_DEVICELIST = "f_devicelist"; //1.3.6
	public static final String F_DEVICEFACE = "f_deviceface"; //1.4.9 & 1.4.10
	public static final String F_DEVICESUBINFO = "f_devicesubinfo"; //1.6.19
	public static final String F_DEVICESUBLIST = "f_devicesublist"; //1.6.20
	
	/*build family data*/
	public static final String F_FAMILYLIST = "f_familylist"; //1.3.3
	public static final String F_FAMILYMEMBER = "f_familymember"; //1.3.4
	public static final String F_MEMBERFACE = "f_memberface"; //1.1.5 & 1.1.6
	
	public static final String F_DEVICE_SETTINGS = "f_device_settings"; //1.3.5
	public static final String F_DEVICE_LOCATION = "f_device_location";//1.6.9
	public static final String F_DEVICE_POWER = "f_device_power";//1.6.21
	
	public static final String F_TODO = "f_todo"; //1.6.5
	
	public static final String F_CARE_REMINDER = "f_care_reminder"; //1.6.13
	public static final String F_MEASURE_REMINDER = "f_measure_reminder"; //1.6.13
	public static final String F_DRUG_REMINDER = "f_drug_reminder"; //1.6.13
	
	public static final String F_GLYCOSE_SET = "f_glycose_set"; //1.9.1
	public static final String F_GLYCOSE_DATA = "f_glycose_data"; //1.9.5
	
	public static final String F_BP_DATA = "f_bp_data"; //1.9.5
	
	
	
	private HashMap<String,DataUpdated> DATA_MAP = new HashMap<String,DataUpdated>();
//	private HashMap<String,Long> TIME_MAP = new HashMap<String,Long>();
	
	public DataManager(HealthApp app){
		mApp = app;
		if(mDBHelper == null){
			String uid = mApp.getUID();
			if(uid != null){
				mDBHelper = new DatabaseHelper(mApp, uid +".db");
			}
		}
		initMap();
		mMsgThread = new HandlerThread("DataMsgBackground");
		mMsgThread.start();
		mHandler = new DataHandler(getBackgroundLooper());
	}
	
	private void logd(String info){
		Log.d(TAG, info);
	}
	
	public DatabaseHelper getDatabaseHelper(){
		return mDBHelper;
	}
	
	private void initMap(){
		synchronized(DATA_MAP){
			DATA_MAP.put(F_USERDATA, new UserDataUpdated(mApp, DataManager.this));
			DATA_MAP.put(F_USERFACE, new UserFaceUpdated(mApp, DataManager.this));
			FamilyListUpdated fmlistdata = new FamilyListUpdated(mApp,DataManager.this);
			DATA_MAP.put(F_FAMILYLIST, fmlistdata);
			DeviceListUpdated devlistdata = new DeviceListUpdated(mApp,DataManager.this);
			DATA_MAP.put(F_DEVICELIST, devlistdata);
			DeviceSubListUpdate devsublistdata = new DeviceSubListUpdate(mApp, this, devlistdata);
			DATA_MAP.put(F_DEVICESUBLIST, devsublistdata);
			DATA_MAP.put(F_DEVICESUBINFO, new DeviceSubInfoUpdate(mApp, this, devsublistdata));
			DATA_MAP.put(F_FAMILYMEMBER, new FamilyMemberUpdated(mApp, DataManager.this, fmlistdata));
			DATA_MAP.put(F_DEVICEFACE, new DeviceFaceUpdated(mApp,DataManager.this, devlistdata));
			DATA_MAP.put(F_MEMBERFACE, new MemberFaceUpdated(mApp,DataManager.this));
			DATA_MAP.put(F_TODO, new ToDoUpdated(mApp,DataManager.this));
			DATA_MAP.put(F_DEVICE_SETTINGS, new DeviceSettingsUpdated(mApp,DataManager.this));
			DATA_MAP.put(F_DEVICE_POWER, new DevicePowerUpdated(mApp, DataManager.this));
			DATA_MAP.put(F_DEVICE_LOCATION, new DeviceLocationQuery(mApp,DataManager.this));
			DATA_MAP.put(F_CARE_REMINDER, new CareReminderUpdated(mApp,DataManager.this));
			DATA_MAP.put(F_MEASURE_REMINDER, new MeasureReminderUpdated(mApp,DataManager.this,devlistdata));
			DATA_MAP.put(F_DRUG_REMINDER, new DrugReminderUpdated(mApp,DataManager.this,devlistdata));		
			DATA_MAP.put(F_GLYCOSE_SET, new GlycoseSetUpdated(mApp,DataManager.this, devlistdata));	
			DATA_MAP.put(F_GLYCOSE_DATA, new GlycoseDataUpdated(mApp,DataManager.this));
			DATA_MAP.put(F_BP_DATA, new BloodPressureDataUpdated(mApp,DataManager.this));
		}
	}
	
	public void releaseAll(){
		synchronized(DATA_MAP){
			Set<String> keys = DATA_MAP.keySet();
			for(String k:keys){
				DataUpdated du = DATA_MAP.get(k);
				du.release();
			}
		}
	}
	
	public Handler getBackGroundHandler(){
		return mHandler;
	}
	
	private Looper getBackgroundLooper(){
		return mMsgThread.getLooper();
	}
	
	public boolean refreshData(String key){
		if(mDBHelper == null)
			return false;
		
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return false;
			}
		
			return du.grabByUser();
		}
	}
	
	public boolean refreshData(String key, Object singleArg){
		if(singleArg == null)
			return false;
		
		//if(singleArg.trim().isEmpty())
		//	return false;
		
		if(mDBHelper == null)
			return false;
		
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return false;
			}
		
			return du.grabByUserWithSingleArgs(singleArg);
		}
	}
	
	public long checkRequestTime(String key){
		
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return -1;
			}
		
			return du.checkRequestTime();
		}
	}
	
	public void setUserData(String key, Object args){
		if(mDBHelper == null)
			return;
		
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return;
			}
			du.setUserData(args);
		}
	}
	
	public Object checkData(String key, String[] args){
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return null;
			}
			
			return du.check(args);
		}
	}
	
	public boolean commitData(String key, Object data){
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return false;
			}
			
			return du.commit(data);
		}
	}
	
	public void startBackGroundDataGrab(){
		logd("startBackGroundDataGrab firstGrab = "+firstGrab);
		if(mDBHelper == null){
			String uid = mApp.getUID();
			if(uid != null){
				mDBHelper = new DatabaseHelper(mApp, uid +".db");
			}
		}
		if(!firstGrab){
			mHandler.removeMessages(DataHandler.MSG_GRAB_DATA);
			Message m = mHandler.obtainMessage(DataHandler.MSG_GRAB_DATA);
			mHandler.sendMessageDelayed(m,300);
			firstGrab = true;
		}
	}
	
	public void stopBackGroundDataGrab(){
		if(firstGrab){
		mHandler.removeMessages(DataHandler.MSG_GRAB_DATA);
		firstGrab = false;
		}
		
		if(mDBHelper != null){
			mDBHelper.closeDB();
			mDBHelper.close();
			mDBHelper = null;
		}
	}
	
	public void downloadAD(){
		mApp.ADDebug("downloadAD");
		mHandler.removeMessages(DataHandler.MSG_DOWNLOAD_AD);
		Message m = mHandler.obtainMessage(DataHandler.MSG_DOWNLOAD_AD);
		mHandler.sendMessageDelayed(m,5000);
	}
	
	class DataHandler extends Handler{
		public static final int MSG_GRAB_DATA = 501;
		public static final int MSG_DOWNLOAD_AD = 502;
		
		DataHandler(Looper looper){
			super(looper);
		}
		
		@Override
		public void handleMessage(Message msg){
			switch(msg.what){
			case MSG_GRAB_DATA:{
				logd("MSG_GRAB_DATA");
				if(mApp.getStatus(HealthApp.STATUS_LOGIN_PROCESSING)){
					logd("MSG_GRAB_DATA:login waiting");
					Message m = obtainMessage(MSG_GRAB_DATA);
					sendMessageDelayed(m, 3000);
					break;
				}
				long delayMs = grabData();
				Message m = obtainMessage(MSG_GRAB_DATA);
				sendMessageDelayed(m, delayMs);
			}break;
			case HealthApp.MSG_NET_RESPONSE:{
				Bundle b = msg.getData();
				String stamp = b.getString("stamp","ooh!No!");
				boolean canceled = b.getBoolean("canceled", false);
				if(stamp.startsWith("DOWNLOAD_AD_ACTION")){
					mApp.ADDebug("DataManager, MSG_NET_RESPONSE from DOWNLOAD_AD_ACTION");
					String sjson = b.getString("json");
					if(sjson != null){
						try {
							JSONObject json = new JSONObject(sjson);
							int code = json.getInt("code");
							if(code == 200){
								String state = json.getString("state");
								if(state.equalsIgnoreCase("00")){
									JSONObject recdata = json.getJSONObject("recdata");
									if(recdata != null){
										if(recdata.has("imagearr")){
											JSONArray adArray = recdata.getJSONArray("imagearr");
											mApp.ADDebug("JSONArray:" + adArray);
											mApp.addADData(adArray);
										}
									}
								}
							}
						} catch (JSONException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}else{
					String key = stamp2Key(stamp);
					String sjson = b.getString("json");
					receiveData(key, stamp, sjson);
				}
			}break;
			case MSG_DOWNLOAD_AD:{
				mApp.ADDebug("MSG_DOWNLOAD_AD");
				if(mApp.isSignIn()){
					
					try {
						JSONObject devjson = (JSONObject) mApp.getDataManager().checkData(DataManager.F_DEVICELIST, null);
						if(devjson != null){
							JSONArray ar = devjson.getJSONArray("array");
							int len = ar.length();
							JSONArray tidArray = new JSONArray();
							for(int i = 0; i < len; i++){
								JSONObject e = ar.getJSONObject(i);
								String tidString = e.getString("tid");
								tidArray.put(tidString);
							}
							if(tidArray.length() > 0){
								Intent si = new Intent(mApp, NetService.class);
								si.setAction(NetService.DOWNLOAD_AD_ACTION);
								si.putExtra("uid", mApp.getUID());
								si.putExtra("tidarray", tidArray.toString());
								Time t = new Time();
								t.setToNow();
								String stamp = "DOWNLOAD_AD_ACTION" + t.toString(); 
								si.putExtra("stamp",stamp);
								mApp.addNetHandler(stamp, this);
								mApp.startService(si);
								break;
							}
						}
					} catch (JSONException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					
				}
				Message m = obtainMessage(MSG_DOWNLOAD_AD);
				sendMessageDelayed(m, 60 * 1000);
			}break;
			default:
				break;
			}
		}
	}
			
    private String stamp2Key(String stamp){
    	if(stamp.startsWith("GET_USER_DATA") || stamp.startsWith("COMMIT_USER_DATA")){
			return F_USERDATA;
		}
    	
    	if(stamp.startsWith("CHECK_USER_FACE_MINE")||stamp.startsWith("DOWNLOAD_USER_FACE_MINE")
    			|| stamp.startsWith("COMMIT_USER_FACE")){
			return F_USERFACE;
		}
    	
    	if(stamp.startsWith("GET_FAMILY_LIST") || stamp.startsWith("COMMIT_BUILD_FAMILY") || stamp.startsWith("COMMIT_ABORT_BY_MEMBER_FA")){
			return F_FAMILYLIST;
		}
    	
    	if(stamp.startsWith("GET_DEVICE_LIST") || stamp.startsWith("COMMIT_DEVICE_NAME")
    			|| stamp.startsWith("COMMIT_DEVICE_ADMIN_ABORT") || stamp.startsWith("COMMIT_DEVICE_ADMIN_APPLY")
    			|| stamp.startsWith("COMMIT_DEVICE_INTEREST_ABORT")){
    		return F_DEVICELIST;
    	}
    	
    	if(stamp.startsWith("GET_DEVICE_SUB_LIST")){
    		return F_DEVICESUBLIST;
    	}
    	
    	if(stamp.startsWith("GET_DEVICE_SUB_INFO")){
    		return F_DEVICESUBINFO;
    	}
    	
    	if(stamp.startsWith("CHECK_DEVICE_FACE")||stamp.startsWith("DOWNLOAD_DEVICE_FACE")
    			||stamp.startsWith("COMMIT_DEV_FACE")){
    		return F_DEVICEFACE;
    	}
    	
    	if(stamp.startsWith("GET_FAMILY_MEMBER")||stamp.startsWith("COMMIT_ADMIN_FA")||stamp.startsWith("COMMIT_ABORT_BY_ADMIN_FA")){
    		return F_FAMILYMEMBER;
    	}
    	
    	if(stamp.startsWith("CHECK_USER_FACE_MEM")||stamp.startsWith("DOWNLOAD_USER_FACE_MEM")){
    		return F_MEMBERFACE;
    	}
    	
    	if(stamp.startsWith("CHECK_DEVICE_SETTINGS") || stamp.startsWith("COMMIT_DEVICE_MOBILENUMBER")){
    		return F_DEVICE_SETTINGS;
    	}
    	
    	if(stamp.startsWith("GET_DEVICE_POWER")){
    		return F_DEVICE_POWER;
    	}
    	
    	if(stamp.startsWith("GET_DEVICE_LOCATION_NEWEST")){
    		return F_DEVICE_LOCATION;
    	}
    	
    	if(stamp.startsWith("GET_TODO_LIST") || stamp.startsWith("COMMIT_TODO")){
    		return F_TODO;
    	}
    	
    	if(stamp.startsWith("GET_CARE_REMINDER") || stamp.startsWith("COMMIT_CARE_REMINDER")){
    		return F_CARE_REMINDER;
    	}    	
    	
    	if(stamp.startsWith("GET_DRUG_REMINDER") || stamp.startsWith("COMMIT_DRUG_REMINDER")){
    		return F_DRUG_REMINDER;
    	}
    	
    	if(stamp.startsWith("GET_GLYCOSE_SET") || stamp.startsWith("COMMIT_GLYCOSE_SET")){
    		return F_GLYCOSE_SET;
    	}
    	
    	if(stamp.startsWith("GET_GLYCOSE_DATA_PERIOD") ){
    		return F_GLYCOSE_DATA;
    	}
    	
    	if(stamp.startsWith("GET_BP_DATA_PERIOD") ){
    		return F_BP_DATA;
    	}
    	
    	return null;
    }
	
	private void receiveData(String key, String stamp, String sjson){
		if((key == null) || key.isEmpty())
			return;
		
		synchronized(DATA_MAP){
			DataUpdated du = DATA_MAP.get(key);
			if(du == null){
				return;
			}
			
			du.receive(stamp, sjson);
		}
	}
	
	private long grabData(){
		synchronized(DATA_MAP){
		Set<String> keys = DATA_MAP.keySet();
		long min = 1000 * 60 * 60;
		int count = 0;
		for(String k:keys){
			DataUpdated du = DATA_MAP.get(k);
			long delay = du.delay();
			if(delay < 0){
				continue;
			}
			if(delay == 0){
				if(du.grab()){
					count++;
					logd("grabData count="+count);
					if(count >= 5){
						return 10 * 1000;
					}
					min = Math.min(min, du.UPDATE_TIME);
				}else{
					min = Math.min(min, 10 * 1000);
				}
			}else{
				min = Math.min(min, delay);
			}
		}
		logd("grabData min = "+min);
		return min;
		}
	}
}
